# -*- coding: utf-8 -*-
# created on 2016/5/12

from mathsolver.functions.base import *
from sympy import Add, Eq, sqrt, solveset, Mul, degree_list
from mathsolver.functions.sympy_utils import get_all_child, target_symbol


# 由完全平方式的定义求参
class ShuYuShiDaiShuShi005(BaseFunction):
    def solver(self, *args):
        poly = args[0].sympify()
        target = target_symbol(poly, args, self)

        assert poly.is_Add
        parts = get_all_child(poly, lambda xx: xx.is_Pow and xx.args[1].is_even)
        assert len(parts) > 0

        eqs = []

        if len(parts) == 1:
            a, h = poly.as_independent(parts[0])
            symbol = parts[0].free_symbols.pop()

            constant = [arg for arg in poly.args if len(arg.free_symbols) == 0]
            if len(constant) == 1:
                constant = constant[0]
            elif len(constant) == 0:
                constant = [arg for arg in poly.args if not arg.has(symbol)][0]

            middle = poly - h - constant
            expr = 2 * h / symbol * sqrt(constant)

        elif len(parts) == 2:
            symbol1 = parts[0].free_symbols.pop()
            symbol2 = parts[1].free_symbols.pop()
            _, h1 = poly.as_independent(parts[0])
            _, h2 = poly.as_independent(parts[1])

            middle = poly - h1 - h2
            expr = 2 * h1 / symbol1 * h2 / symbol2
        else:
            raise ValueError

        middle = middle.simplify()
        assert middle.is_Mul or middle.is_Symbol
        eqs.append(Eq(expr, middle))
        eqs.append(Eq(expr, -middle))

        if middle.is_Mul and middle.args[0].is_negative:
            self.steps.append(["由完全平方式的定义得：", "%s = \\pm %s" % (new_latex(expr), new_latex(- middle))])
        else:
            self.steps.append(["由完全平方式的定义得：", "%s = \\pm %s" % (new_latex(expr), new_latex(middle))])

        answer = []
        for eq in eqs:
            answer.extend(solveset(eq, target))

        self.steps.append(["解得,", self.output_jie(answer, target)])
        self.output.append(BaseSymbolValue({target: answer}))
        self.label.add("由完全平方式的定义求参")
        return self


# 由同类项的定义求参
class ShuYuShiDaiShuShi006(BaseFunction):
    def solver(self, *args):
        poly1 = args[0].sympify()
        poly2 = args[1].sympify()

        parts1 = get_all_child(poly1, lambda xx: xx.is_Pow or xx.is_Symbol)
        parts2 = get_all_child(poly2, lambda xx: xx.is_Pow or xx.is_Symbol)

        parts1 = dict([(part.args[0], part.args[1]) if part.is_Pow else (part, 1) for part in parts1])
        parts2 = dict([(part.args[0], part.args[1]) if part.is_Pow else (part, 1) for part in parts2])
        # assert parts1.keys() == parts2.keys(), "Same symbols needed!"

        eqs = []
        for key in parts1:
            if key in parts2:
                f1, f2 = parts1[key], parts2[key]
                if (f1 - f2).free_symbols:
                    eqs.append([f1, f2])

        if len(eqs) > 1:
            self.steps.append(["由同类项的定义，得：", self.output_eqs(eqs)])
            self.output.append(BaseEqs(eqs))
        elif len(eqs) == 1:
            self.steps.append(["由同类项的定义，得：", new_latex(eqs[0])])
            self.output.append(BaseEq(eqs[0]))

        self.label.add("由同类项的定义求参")
        return self


# 整体代入计算
class ShuYuShiDaiShuShiQiaoSuan(BaseFunction):
    @staticmethod
    def dairu(expr, answer):
        for i in range(3):
            expr = expr.subs(answer)
        return expr

    def solver(self, *args):
        """
        已知方程，求代数的值，eg. ShuYuShiDaiShuShiQiaoSuan().solver(BasePoly("3-x-2*y"), BaseEq(["2*x + 4*y","3"]))
        :param args:
        :return:
        """
        target = args[0].sympify()
        f1, f2 = args[1].sympify()

        if not f2.is_zero:
            expr = f1 - f2
        else:
            expr = f1

        assert expr.is_Add and target.is_Add
        expr_constant = [arg for arg in expr.args if len(arg.free_symbols) == 0][0]
        target_constant = [arg for arg in target.args if len(arg.free_symbols) == 0][0]

        expr_sub = expr - expr_constant
        target_sub = target - target_constant

        ratio = (target_sub / expr_sub).simplify()
        assert len(ratio.free_symbols) == 0

        if not expr_constant.is_zero and -expr_constant != f2:
            self.steps.append(["", "%s = %s" % (new_latex(expr_sub), new_latex(-expr_constant))])

        value = -expr_constant * ratio
        self.steps.append(["", "将%s的值带入代数式，得" % new_latex(expr_sub)])
        self.steps.append(["", "%s" % new_latex(Add._from_args([value, target_constant]))])
        number = value + target_constant
        self.steps.append(["", "= %s" % new_latex(number)])
        self.label.add("整体代入计算")
        self.output.append(BaseNumber(number))
        return self


# 求单项式的系数
class DaiShuShiXiShu(BaseFunction):
    def solver(self, *args):
        poly = args[0].sympify().simplify()
        assert poly.is_Mul
        xishu = [arg for arg in poly.args if len(arg.free_symbols) == 0]
        assert len(xishu) > 0
        xishu = Mul._from_args(xishu)
        self.steps.append(["", "系数为%s" % new_latex(xishu)])
        self.label.add("求单项式的系数")
        self.output.append(BaseNumber(xishu))
        return self


# 求单项式的次数
class DaiShuShiCiShu(BaseFunction):
    def solver(self, *args):
        poly = args[0].sympify().simplify()
        num = sum(degree_list(poly))

        self.steps.append(["", "次数为%s" % new_latex(num)])
        self.label.add("求单项式的次数")
        self.output.append(BaseNumber(num))
        return self


# 多项式..是次项式.
class DaiShuShiXiangShi(BaseFunction):
    def get_cishu(self, expr, cishu):
        assert not expr.is_Add
        if expr.is_Pow:  # 表达式是指数项时，直接返回指数
            return expr.args[1]
        elif expr.is_Mul:  # 表达式由乘/除号连接时，再次拆分表达式求每项次数的总和
            for item in expr.args:
                cishu = cishu + self.get_cishu(item, cishu)
            return cishu
        elif isinstance(expr, Symbol):  # 表达式是单个字母时，次数返回1
            return 1
        else:  # 其他情况，包括常数项时，次数返回0
            return 0

    def solver(self, *args):
        """
        多项式%s是%s次%s项式
        :param args:
        :return:
        """
        cishu_zuigao = 0
        # 将表达式完全展开
        expr = args[0].sympify().expand()
        if not expr.is_Add:  # 表达式是单项式的情况
            xiangshu = 1
            cishu_zuigao = self.get_cishu(expr, 0)
        else:  # 表达式是多项式的情况
            xiangshu = len(expr.args)
            for item in expr.args:  # 遍历表达式中的项，计算每项的次数
                if self.get_cishu(item, 0) > cishu_zuigao:
                    cishu_zuigao = self.get_cishu(item, 0)
        self.steps.append(
            ["依题意，", "表达式%s是%s次%s项式" % (new_latex(args[0].sympify()), new_latex(cishu_zuigao), new_latex(xiangshu))])
        return self


# 两个代数式值相等
class DaiShuShiXiangDeng(BaseFunction):
    def solver(self, *args):
        poly1 = args[0].sympify().simplify()
        poly2 = args[1].sympify().simplify()
        eq = [poly1, poly2]
        self.steps.append(["由题意,得", self.output_eq(eq)])
        self.output.append(BaseEq(eq))
        self.label.add("代数式值相等")
        return self


# 代数式值等于某个数
class DaiShuShi007(BaseFunction):
    def solver(self, *args):
        poly = args[0].sympify()
        answer = args[1].value

        eq = [poly, answer]
        self.steps.append(["由题意,得", self.output_eq(eq)])
        self.output.append(BaseEq(eq))
        return self


# 代数式值大于某个代数式
class DaiShuShi008(BaseFunction):
    op = ">"
    label_answer = "代数式大于某个代数式求参"

    def solver(self, *args):
        poly1 = args[0].sympify()
        poly2 = args[1].sympify()
        if self.op == "=":
            eq = [poly1, poly2]
            self.steps.append(["由题意,得", self.output_eq(eq)])
            self.output.append(BaseEq(eq))
            self.label.add(self.label_answer)
        else:
            ineq = [poly1, self.op, poly2]
            self.steps.append(["由题意,得", self.output_eq(ineq)])
            self.output.append(BaseIneq(ineq))
            self.label.add(self.label_answer)
        return self


# 代数式值不大于某个代数式
class DaiShuShi009(DaiShuShi008):
    op = "<="
    label_answer = "代数式值不大于某个代数式求参"


# 代数式值不小于某个代数式
class DaiShuShi010(DaiShuShi008):
    op = ">="
    label_answer = "代数式值不小于某个代数式求参"


# 代数式值等于某个代数式
class DaiShuShi011(DaiShuShi008):
    op = "="
    label_answer = "代数式值等于某个代数式"


# 代数式约分
class ShuYuShiDaiShuShiYueFen(BaseFunction):
    def solver(self, *args):
        """
        代数式约分
        :param args:
        :return:
        """
        poly = args[0].sympify()
        poly_cancel = poly.cancel()
        self.steps.append([new_latex(poly), "= %s" % new_latex(poly_cancel)])
        self.output.append(BaseNumber(poly_cancel))
        return self


if __name__ == '__main__':
    pass
